package com.tlgen.orm.utils.orm;

import com.tlgen.orm.annotation.CursorField;
import com.tlgen.orm.annotation.Id;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static com.tlgen.orm.constant.QueryOperatorConstant.DEFAULT_CURSOR_FIELD;

@Slf4j
public class CursorUtils {

    // 高性能缓存：类 -> 游标字段名
    private static final ConcurrentMap<Class<?>, String> CURSOR_FIELD_CACHE = new ConcurrentHashMap<>();

    // 高性能缓存：类+字段名 -> 字段对象
    private static final ConcurrentMap<String, Field> FIELD_CACHE = new ConcurrentHashMap<>();

    // 高性能缓存：类 -> 是否已扫描（避免重复扫描）
    private static final ConcurrentMap<Class<?>, Boolean> SCANNED_CLASSES = new ConcurrentHashMap<>();

    // 新增：缓存类 -> 所有字段映射（字段名 -> Field对象）
    private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Field>> CLASS_FIELDS_CACHE =
            new ConcurrentHashMap<>();

    /**
     * 递归查找带有@CursorField注解的字段（带缓存）
     */
    public static <T> String getCursorField(Class<T> tClass) {
        // 优先从缓存获取
        return CURSOR_FIELD_CACHE.computeIfAbsent(tClass, cls -> {
            String fieldName = findCursorField(cls);
            log.debug("Cached cursor field for {}: {}", cls.getName(), fieldName);
            return fieldName;
        });
    }

    /**
     * 实际查找游标字段（递归）
     */
    private static String findCursorField(Class<?> clazz) {
        Class<?> currentClass = clazz;
        while (currentClass != null && currentClass != Object.class) {
            // 如果已经扫描过该类，跳过
            if (SCANNED_CLASSES.containsKey(currentClass)) {
                currentClass = currentClass.getSuperclass();
                continue;
            }

            // 扫描当前类
            for (Field field : currentClass.getDeclaredFields()) {
                if (isCursorField(field)) {
                    // 标记所有父类为已扫描
                    markSuperClassesScanned(currentClass);
                    return field.getName();
                }
            }

            // 标记当前类为已扫描
            SCANNED_CLASSES.put(currentClass, true);
            currentClass = currentClass.getSuperclass();
        }
        return DEFAULT_CURSOR_FIELD;
    }

    /**
     * 标记所有父类为已扫描
     */
    private static void markSuperClassesScanned(Class<?> clazz) {
        Class<?> current = clazz;
        while (current != null && current != Object.class) {
            SCANNED_CLASSES.putIfAbsent(current, true);
            current = current.getSuperclass();
        }
    }

    /**
     * 检查字段是否适合作为游标字段
     */
    private static boolean isCursorField(Field field) {
        if (!field.isAnnotationPresent(CursorField.class)) {
            // 兜底使用@Id主键字段
            if (field.isAnnotationPresent(Id.class)) {
                return true;
            }
            return false;
        }

        Class<?> type = field.getType();
        return type == long.class || type == Long.class ||
                type == int.class || type == Integer.class ||
                type == java.util.Date.class ||
                type == java.time.LocalDateTime.class ||
                type == java.time.Instant.class;
    }

    /**
     * 从实体对象中提取游标值（带缓存）
     */
    public static <T> Long extractCursorValue(T entity, String cursorField) {
        if (entity == null || cursorField == null) return null;

        Field field = getCachedField(entity.getClass(), cursorField);
        if (field == null) return null;

        try {
            Object value = field.get(entity);
            return convertToLong(value);
        } catch (Exception e) {
            log.error("Failed to extract cursor value", e);
            return null;
        }
    }

    /**
     * 新增：获取缓存的Field对象
     *
     * @param clazz 实体类
     * @param fieldName 字段名
     * @return Field对象，如果找不到则返回null
     */
    public static Field getCachedField(Class<?> clazz, String fieldName) {
        if (clazz == null || fieldName == null) return null;

        String cacheKey = clazz.getName() + "#" + fieldName;

        // 从缓存获取字段对象
        return FIELD_CACHE.computeIfAbsent(cacheKey, key -> {
            try {
                // 递归查找字段
                Class<?> currentClass = clazz;
                while (currentClass != null && currentClass != Object.class) {
                    try {
                        Field f = currentClass.getDeclaredField(fieldName);
                        f.setAccessible(true);
                        return f;
                    } catch (NoSuchFieldException e) {
                        currentClass = currentClass.getSuperclass();
                    }
                }
                throw new NoSuchFieldException("Field not found: " + fieldName);
            } catch (Exception e) {
                log.error("Failed to cache field", e);
                return null;
            }
        });
    }

    /**
     * 获取类的主游标字段对象（带缓存）
     * - 优先返回 @CursorField 注解的字段
     * - 其次返回 @Id 注解的字段
     * - 最后返回 "id" 字段
     */
    public static Field getCachedCursorField(Class<?> clazz) {
        if (clazz == null) return null;

        // 缓存键：类名 + "#cursor_field"
        String cacheKey = clazz.getName() + "#cursor_field";

        return FIELD_CACHE.computeIfAbsent(cacheKey, key -> {
            // 1. 优先查找 @CursorField 字段
            for (Field field : getAllCachedFields(clazz).values()) {
                if (field.isAnnotationPresent(CursorField.class)) {
                    field.setAccessible(true);
                    return field;
                }
            }

            // 2. 其次查找 @Id 主键字段
            for (Field field : getAllCachedFields(clazz).values()) {
                if (field.isAnnotationPresent(Id.class)) {
                    field.setAccessible(true);
                    return field;
                }
            }

            // 3. 最后查找默认 "id" 字段
            try {
                Field defaultField = clazz.getDeclaredField("id");
                defaultField.setAccessible(true);
                return defaultField;
            } catch (NoSuchFieldException e) {
                log.warn("Default 'id' field not found in class: {}", clazz.getName());
                return null;
            }
        });
    }

    /**
     * 新增：获取类的所有字段映射（带缓存）
     *
     * @param clazz 实体类
     * @return 字段名到Field对象的映射
     */
    public static ConcurrentMap<String, Field> getAllCachedFields(Class<?> clazz) {
        return CLASS_FIELDS_CACHE.computeIfAbsent(clazz, cls -> {
            ConcurrentMap<String, Field> fieldMap = new ConcurrentHashMap<>();
            Class<?> currentClass = cls;

            while (currentClass != null && currentClass != Object.class) {
                for (Field field : currentClass.getDeclaredFields()) {
                    field.setAccessible(true);
                    fieldMap.put(field.getName(), field);
                }
                currentClass = currentClass.getSuperclass();
            }

            return fieldMap;
        });
    }

    /**
     * 新增：获取特定字段的Field对象（从类字段映射中获取）
     *
     * @param clazz 实体类
     * @param fieldName 字段名
     * @return Field对象，如果找不到则返回null
     */
    public static Field getFieldFromClassCache(Class<?> clazz, String fieldName) {
        ConcurrentMap<String, Field> fieldMap = getAllCachedFields(clazz);
        return fieldMap.get(fieldName);
    }

    /**
     * 将各种类型转换为Long值
     */
    private static Long convertToLong(Object value) {
        if (value == null) return null;

        if (value instanceof Number) {
            return ((Number) value).longValue();
        } else if (value instanceof java.util.Date) {
            return ((java.util.Date) value).getTime();
        } else if (value instanceof java.time.Instant) {
            return ((java.time.Instant) value).toEpochMilli();
        } else if (value instanceof java.time.LocalDateTime) {
            return ((java.time.LocalDateTime) value).atZone(java.time.ZoneId.systemDefault())
                    .toInstant().toEpochMilli();
        }
        return null;
    }

    /**
     * 清除缓存（用于开发环境热部署）
     */
    public static void clearCache() {
        CURSOR_FIELD_CACHE.clear();
        FIELD_CACHE.clear();
        SCANNED_CLASSES.clear();
        CLASS_FIELDS_CACHE.clear();
        log.info("CursorUtils cache cleared");
    }

}